
package jard.webshop.jsfbeans;

import jard.webshop.management.CategoryManagement;
import jard.webshop.nbp.Category;
import jard.webshop.util.Utils;
import java.io.Serializable;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import org.primefaces.event.NodeSelectEvent;
import org.primefaces.model.DefaultTreeNode;
import org.primefaces.model.TreeNode;

/**
 *
 * @author CJP
 */
@ManagedBean(name = "categoryBackingBean")
@ViewScoped // This works but maybe other scopes could also work?
public class CategoryBackingBean implements Serializable {

    private static CategoryManagement cm = null;
    private TreeNode root;
    private TreeNode selectedNode = new DefaultTreeNode();
    private String categoryName = "";
    private String newCategoryName = "";
    private String message = "";

    public CategoryBackingBean() {
        cm = CategoryManagement.getInstance();
        System.out.println("Constructor of categoryBackingBean");
        init();
    }

    @PostConstruct
    private void init() {
        System.out.println("Init of categoryBackingBean");
        root = new DefaultTreeNode("Root", null);
        List<Category> roots = cm.getRootcategories();
        for (Category c : roots) {
            System.out.println("Calling buildSubTree for " + c);
            buildSubTree(root, c);
        }
    }

    /**
     * Recursive method that constructs a tree of TreeNodes
     * 
     * @param parentRoot
     * @param cat Category for this node
     * @return TreeNode, not used though
     */
    private TreeNode buildSubTree(TreeNode parentRoot, Category cat) {
        System.out.println("buildSubTree for " + cat.getName());
        TreeNode localRoot = new DefaultTreeNode(cat, parentRoot);
        for (Category c : cat.getSubcategories()) {
            buildSubTree(localRoot, c);
        }
        localRoot.setExpanded(true);
        return localRoot;
    }

    public TreeNode getRoot() {
        return root;
    }

    /**
     * Writes changes in the UI markings to bean variables.
     * 
     * @param obj NodeSelectEvent that we examine for new values, or null.
     */
    public void nodeListener(NodeSelectEvent obj) {
        System.out.println("We're in nodeListener, looking at a NodeSelectEvent " + obj.getTreeNode());
        System.out.println("On Selected node => " + selectedNode);
        if(selectedNode == null) {
            categoryName = "";
            return;
        }
        Category selectedCat = (Category) selectedNode.getData();
        categoryName = selectedCat.getName();
    }

    public TreeNode getSelectedNode() {
        return selectedNode;
    }

    public void setSelectedNode(TreeNode selectedNode) {
        this.selectedNode = selectedNode;
    }

    public String getCategoryName() {
        return categoryName;
    }

    public void setCategoryName(String categoryName) {
        this.categoryName = categoryName;
    }

    /**
     * Adds a category to the database and updates the UI.
     */
    public void addCategory() {
        if (newCategoryName.isEmpty()) {
            message = "No new name entered!";
            Utils.growl("Failed",message);
            return;
        }
        if (selectedNode == null || selectedNode.getData() == null) {
            Category newCat = new Category(newCategoryName);
            cm.addCategory(newCat);
            init();
            return;
        }
        System.out.println("adding new category " + newCategoryName);
        Category localRoot = (Category) selectedNode.getData();
        Category newCat = new Category(newCategoryName);
        System.out.println("Adding it as a sub to " + localRoot);
        localRoot.addSubcategory(newCat);
        System.out.println(localRoot + " has these subcategories");
        for (Category g : localRoot.getSubcategories()) {
            System.out.println("|" + g);
        }
        cm.saveCategory(localRoot);
        cm.addCategory(newCat);
        init();
        newCategoryName = "";
    }
    
    public void changeCategory() {
        if (selectedNode == null || selectedNode.getData() == null) {
            message = "No category marked!";
            Utils.growl("Failed",message);
            return;
        }
        if (newCategoryName.isEmpty()) {
            message = "No new name entered!";
            Utils.growl("Failed",message);
            return;
        }
        System.out.println("changing category name" + newCategoryName);
        Category localRoot = (Category) selectedNode.getData();
        localRoot.setName(newCategoryName);
        cm.saveCategory(localRoot);
        init();
        categoryName = "";
        newCategoryName = "";
    }

    /**
     * Removes the category marked in the UI layer, if and only if it has no 
     * subcategories and no products reference it. Displays error message
     * if one or more of these requirements are not met.
     * 
     */
    public void removeCategory() {
        System.out.println("removeCategory()!!");
        if (selectedNode == null) {
            System.out.println("selectedNode was null!");
            return;
        }
        System.out.println("removing old category ");
        Category localRoot = (Category) selectedNode.getData();
        if (localRoot == null) {
            System.out.println("localRoot was null so we... couldn't erase it.");
            return;
        }
        Category parent = localRoot.getParent();
        System.out.println("Removing " + localRoot + " from " + parent);
        Boolean result = cm.removeIfOrphan(localRoot);
        System.out.println("Could " + localRoot + " be deleted? " + result);
        if (result == false) {
            message = "Could not remove Category because it was either not empty"
                    + " or in use by some products.";
            Utils.growl("Failed",message);
            return;
        }
        System.out.println("cm.isPersisted(localRoot) " + cm.isPersisted(localRoot) + "(should be false)");
        if(parent != null) {
            System.out.println("Saving parent to make it reflect the removed child.");
            //cm.saveCategory(parent);
        }

        init();
        categoryName = "";
        //return "main.jsf";
    }

    public String getNewCategoryName() {
        return newCategoryName;
    }

    public void setNewCategoryName(String newCategoryName) {
        System.out.println("Setting newCategoryName " + newCategoryName);
        this.newCategoryName = newCategoryName;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    
}
